source("../lib/plot-element.R")

并列和堆叠, Group and Stack

Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
bar_data <- data.table(Animals, SF_Zoo, LA_Zoo)

p0 <- create_canvas(data = bar_data, x = ~Animals) %>%
  config(mathjax = "cdn") %>%
  add_bars(
    y = ~SF_Zoo,
    name = "SF Zoo"
  ) %>%
  add_bars(
    y = ~LA_Zoo,
    name = "LA Zoo"
  ) %>%
  layout(
    xaxis = list(title = "Animals"),
    yaxis = list(title = "Count")
  )

p <- p0 %>%
  layout(barmode = "group")
p
p <- p0 %>%
  layout(barmode = "stack")
p

条上显示数值/文本

x <- c("Product A", "Product B", "Product C")
y <- c(20, 14, 23)
y2 <- c(16, 12, 27)
text <- c("27% market share", "24% market share", "19% market share")
bar_data <- data.table(x, y, y2, text)

p0 <- create_canvas(
  data = bar_data, x = ~x,
  # color = I("black"),
  # I('...') 的定义会规定所有颜色,不用把marker的color, line的color等全部写一遍
  marker = list(
    color = "rgb(158,202,225)",
    line = list(
      color = "rgb(8,48,107)",
      width = 1.5
    )
  )
) %>%
  layout(
    title = list(
      text = "January 2013 Sales Report",
      pad = list(t = 40)
    ),
    legend = list(
      bgcolor = "white",
      xanchor = "left"
    )
  ) %>%
  config(mathjax = "cdn")

p <- p0 %>%
  add_bars(y = ~y, text = ~text)
p
p <- p0 %>%
  add_bars(y = ~y, text = ~y)
p
p <- p0 %>%
  add_bars(y = ~y, text = ~y, name = "y1") %>%
  add_bars(y = ~y2, text = ~y2, name = "y2") %>%
  layout(barmode = "group")
p

轴刻度标签倾斜, Rotated Labels

x <- c(
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December"
)
y1 <- c(20, 14, 25, 16, 18, 22, 19, 15, 12, 16, 14, 17)
y2 <- c(19, 14, 22, 14, 16, 19, 15, 14, 10, 12, 12, 16)
data <- data.table(x, y1, y2)

# The default order will be alphabetized unless specified as below:
data$x <- factor(data$x, levels = data[["x"]])

p0 <- create_canvas(data = data, x = ~x) %>%
  layout(
    legend = list(
      bgcolor = "white",
      xanchor = "left"
    )
  )

p <- p0 %>%
  add_bars(
    y = ~y1, name = "Primary Product",
    marker = list(color = "rgb(49,130,189)")
  ) %>%
  add_bars(
    y = ~y2, name = "Secondary Product",
    marker = list(color = "rgb(204,204,204)")
  ) %>%
  layout(
    xaxis = list(tickangle = -45),
    barmode = "group"
  )
p

自定义每个条的颜色

x <- c("Feature A", "Feature B", "Feature C", "Feature D", "Feature E")
y <- c(20, 14, 23, 25, 22)
data <- data.table(x, y)

p <- create_canvas(data = data) %>%
  add_bars(
    x = ~x, y = ~y,
    marker = list(
      color = c(
        "rgba(204,204,204,1)", "rgba(222,45,38,0.8)",
        "rgba(204,204,204,1)", "rgba(204,204,204,1)",
        "rgba(204,204,204,1)"
      )
    )
  ) %>%
  layout(
    title = list(
      text = "Least Used Features",
      pad = list(t = 40)
    )
  )
p

自定义每个条的宽度

x <- c(1, 2, 3, 5.5, 10)
y <- c(10, 8, 6, 4, 2)
width <- c(0.8, 0.8, 0.8, 3.5, 4)
data <- data.table(x, y, width)

p <- create_canvas(data = data) %>%
  add_bars(
    x = ~x,
    y = ~y,
    width = ~width
  )
p

自定义每个条的基线高度,Base

p <- create_canvas(x = c("2016", "2017", "2018")) %>%
  add_bars(
    y = c(500, 600, 700),
    base = c(-500, -600, -700),
    marker = list(
      color = "orangered"
    ),
    name = "expenses"
  ) %>%
  add_bars(
    y = c(300, 400, 700),
    # base = 0,
    marker = list(
      color = "royalblue"
    ),
    name = "revenue"
  ) %>%
  layout(
    legend = list(
      bgcolor = "white",
      xanchor = "left"
    )
  )
p

映射变量为颜色

data <- ggplot2::diamonds %>%
  count(cut, clarity)
data
#> # A tibble: 40 x 3
#>    cut   clarity     n
#>    <ord> <ord>   <int>
#>  1 Fair  I1        210
#>  2 Fair  SI2       466
#>  3 Fair  SI1       408
#>  4 Fair  VS2       261
#>  5 Fair  VS1       170
#>  6 Fair  VVS2       69
#>  7 Fair  VVS1       17
#>  8 Fair  IF          9
#>  9 Good  I1         96
#> 10 Good  SI2      1081
#> # ... with 30 more rows
p <- create_canvas(data = data) %>%
  add_bars(x = ~cut, y = ~n, color = ~clarity) %>%
  layout(
    legend = list(
      bgcolor = "white",
      xanchor = "left"
    )
  )
p

定义条间距

x <- c(
  1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
)
roW <- c(
  219, 146, 112, 127, 124, 180, 236, 207, 236,
  263, 350, 430, 474, 526, 488, 537, 500, 439
)
China <- c(
  16, 13, 10, 11, 28, 37, 43, 55, 56,
  88, 105, 156, 270, 299, 340, 403, 549, 499
)
data <- data.table(x, roW, China)

p0 <- create_canvas(data = data, x = ~x)

p <- p0 %>%
  add_bars(
    y = ~roW, name = "Rest of the World",
    marker = list(color = "rgb(55, 83, 109)")
  ) %>%
  add_bars(
    y = ~China, name = "China",
    marker = list(color = "rgb(26, 118, 255)")
  ) %>%
  layout(
    title = list(text = "US Export of Plastic Scrap"),
    xaxis = list(
      tickfont = list(
        size = 14,
        color = "rgb(107, 107, 107)"
      )
    ),
    yaxis = list(
      title = list(text = "USD (millions)"),
      titlefont = list(
        size = 16,
        color = "rgb(107, 107, 107)"
      ),
      tickfont = list(
        size = 14,
        color = "rgb(107, 107, 107)"
      )
    ),
    legend = list(
      x = 0, xanchor = "left", y = 1,
      bgcolor = "rgba(255, 255, 255, 0)" # 透明度为0
    ),
    barmode = "group", bargap = 0.15,
    bargroupgap = 0.1 # 该属性明明起作用,还是报warning说没有这个属性
  )
p

瀑布图, Waterfall

x <- c(
  "Product<br>Revenue", "Services<br>Revenue", "Total<br>Revenue",
  "Fixed<br>Costs", "Variable<br>Costs", "Total<br>Costs", "Total"
)
y <- c(400, 660, 660, 590, 400, 400, 340)
base <- c(0, 430, 0, 570, 370, 370, 0)
revenue <- c(430, 260, 690, 0, 0, 0, 0)
costs <- c(0, 0, 0, 120, 200, 320, 0)
profit <- c(0, 0, 0, 0, 0, 0, 370)
text <- c("$430K", "$260K", "$690K", "$-120K", "$-200K", "$-320K", "$370K")
data <- data.table(x, base, revenue, costs, profit, text)

# The default order will be alphabetized unless specified as below:
data$x <- factor(data$x, levels = data[["x"]])

p <- create_canvas(data = data, x = ~x) %>%
  # 堆叠层,要透明,才能看起来像什么都没有
  add_bars(
    y = ~base, name = "",
    marker = list(color = "rgba(1,1,1,0)")
  ) %>%
  add_bars(
    y = ~revenue, name = "revenue",
    marker = list(
      color = "rgba(55, 128, 191, 0.7)",
      line = list(
        color = "rgba(55, 128, 191, 0.7)",
        width = 2
      )
    )
  ) %>%
  add_bars(
    y = ~costs, name = "cost",
    marker = list(
      color = "rgba(219, 64, 82, 0.7)",
      line = list(
        color = "rgba(219, 64, 82, 1.0)",
        width = 2
      )
    )
  ) %>%
  add_bars(
    y = ~profit, name = "profit",
    marker = list(
      color = "rgba(50, 171, 96, 0.7)",
      line = list(
        color = "rgba(50, 171, 96, 1.0)",
        width = 2
      )
    )
  ) %>%
  layout(
    title = list(text = "Annual Profit - 2015"),
    barmode = "stack",
    showlegend = TRUE
  ) %>%
  add_annotations(
    text = ~text,
    x = ~x,
    y = ~y,
    xref = "x",
    yref = "y",
    font = list(
      family = "Arial",
      size = 14,
      color = "rgba(245, 246, 249, 1)"
    ),
    showarrow = FALSE
  )
p

水平条形图, Horizontal

y <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
data <- data.table(y, SF_Zoo, LA_Zoo)

create_canvas(data = data) %>%
  add_bars(
    x = ~SF_Zoo,
    y = ~y,
    orientation = "h"
  )
p <- create_canvas(data = data, y = ~y, orientation = "h") %>%
  add_trace(
    x = ~SF_Zoo, name = "SF Zoo",
    marker = list(
      color = "rgba(246, 78, 139, 0.6)",
      line = list(
        color = "rgba(246, 78, 139, 1.0)",
        width = 3
      )
    )
  ) %>%
  add_trace(
    x = ~LA_Zoo, name = "LA Zoo",
    marker = list(
      color = "rgba(58, 71, 80, 0.6)",
      line = list(
        color = "rgba(58, 71, 80, 1.0)",
        width = 3
      )
    )
  ) %>%
  layout(barmode = "stack")
p
y <- c(
  "The course was effectively<br>organized",
  "The course developed my<br>abilities and skills for<br>the subject",
  "The course developed my<br>ability to think critically about<br>the subject",
  "I would recommend this<br>course to a friend"
)
x1 <- c(21, 24, 27, 29)
x2 <- c(30, 31, 26, 24)
x3 <- c(21, 19, 23, 15)
x4 <- c(16, 15, 11, 18)
x5 <- c(12, 11, 13, 14)

data <- data.table(y, x1, x2, x3, x4, x5)

top_labels <- c(
  "Strongly<br>agree", "Agree", "Neutral",
  "Disagree", "Strongly<br>disagree"
)

p0 <- create_canvas(
  data = data, y = ~y, orientation = "h",
  marker = list(line = list(
    color = "rgb(248, 248, 249)",
    width = 1
  ))
)

p <- p0 %>%
  add_bars(x = ~x1, marker = list(color = "rgba(38, 24, 74, 0.8)")) %>%
  add_bars(x = ~x2, marker = list(color = "rgba(71, 58, 131, 0.8)")) %>%
  add_bars(x = ~x3, marker = list(color = "rgba(122, 120, 168, 0.8)")) %>%
  add_bars(x = ~x4, marker = list(color = "rgba(164, 163, 204, 0.85)")) %>%
  add_bars(x = ~x5, marker = list(color = "rgba(190, 192, 213, 1)")) %>%
  layout(
    xaxis = list(
      showgrid = FALSE,
      showline = FALSE,
      showticklabels = FALSE,
      zeroline = FALSE,
      domain = c(0.15, 1) # plot 15% 的宽度空出来
    ),
    yaxis = list(
      showgrid = FALSE,
      showline = FALSE,
      showticklabels = FALSE,
      zeroline = FALSE
    ),
    barmode = "stack",
    paper_bgcolor = "rgb(248, 248, 255)",
    plot_bgcolor = "rgb(248, 248, 255)",
    margin = list(l = 120, r = 10, t = 140, b = 80),
    showlegend = FALSE
  ) %>%
  add_annotations(
    xref = "paper", x = 0.14, # plot 14% 的位置
    xanchor = "right", align = "right", # 右对齐
    yref = "y", y = ~y, # 对准y轴上的y坐标
    text = ~y,
    font = list(
      family = "Arial", size = 12,
      color = "rgb(67, 67, 67)"
    ),
    showarrow = FALSE
  ) %>%
  # labeling the percentages of each bar (x_axis)
  add_annotations(
    xref = "x", yref = "y",
    x = x1 / 2, y = y,
    text = str_c(data$x1, "%"),
    font = list(
      family = "Arial", size = 12,
      color = "rgb(248, 248, 255)"
    ),
    showarrow = FALSE
  ) %>%
  add_annotations(
    xref = "x", yref = "y",
    x = x1 + x2 / 2, y = y,
    text = str_c(data$x2, "%"),
    font = list(
      family = "Arial", size = 12,
      color = "rgb(248, 248, 255)"
    ),
    showarrow = FALSE
  ) %>%
  add_annotations(
    xref = "x", yref = "y",
    x = x1 + x2 + x3 / 2, y = y,
    text = str_c(data$x3, "%"),
    font = list(
      family = "Arial", size = 12,
      color = "rgb(248, 248, 255)"
    ),
    showarrow = FALSE
  ) %>%
  add_annotations(
    xref = "x", yref = "y",
    x = x1 + x2 + x3 + x4 / 2, y = y,
    text = str_c(data$x4, "%"),
    font = list(
      family = "Arial", size = 12,
      color = "rgb(248, 248, 255)"
    ),
    showarrow = FALSE
  ) %>%
  add_annotations(
    xref = "x", yref = "y",
    x = x1 + x2 + x3 + x4 + x5 / 2, y = y,
    text = str_c(data$x5, "%"),
    font = list(
      family = "Arial", size = 12,
      color = "rgb(248, 248, 255)"
    ),
    showarrow = FALSE
  ) %>%
  # labeling the first Likert scale (on the top)
  add_annotations(
    xref = "x", x = c(
      21 / 2, 21 + 30 / 2, 21 + 30 + 21 / 2,
      21 + 30 + 21 + 16 / 2, 21 + 30 + 21 + 16 + 12 / 2
    ),
    yref = "paper", y = 1.15,
    text = top_labels,
    font = list(
      family = "Arial", size = 12,
      color = "rgb(67, 67, 67)"
    ),
    showarrow = FALSE
  )
p

两张图合并

y <- c(
  "Japan", "United Kingdom", "Canada", "Netherlands",
  "United States", "Belgium", "Sweden", "Switzerland"
)
x_saving <- c(1.3586, 2.2623, 4.9822, 6.5097, 7.4812, 7.5133, 15.2148, 17.5205)
x_net_worth <- c(
  93453.92, 81666.57, 69889.62, 78381.53,
  141395.3, 92969.02, 66090.18, 122379.3
)
data <- data.table(y, x_saving, x_net_worth)

p1 <- create_canvas(data = data) %>%
  add_bars(
    x = ~x_saving, y = ~ reorder(y, x_saving), orientation = "h",
    name = "Household savings, percentage of household disposable income",
    marker = list(
      color = "rgba(50, 171, 96, 0.6)",
      line = list(color = "rgba(50, 171, 96, 1)", width = 1)
    )
  ) %>%
  layout(
    yaxis = list(
      showgrid = FALSE, showline = FALSE,
      showticklabels = TRUE, domain = c(0, 0.85)
    ),
    xaxis = list(
      zeroline = FALSE, showline = FALSE,
      showticklabels = TRUE, showgrid = TRUE
    )
  ) %>%
  add_annotations(
    xref = "x1", yref = "y",
    x = x_saving + 2,
    y = y,
    text = paste(round(x_saving, 2), "%"),
    font = list(family = "Arial", size = 12, color = "rgb(50, 171, 96)"),
    showarrow = FALSE
  )

p2 <- create_canvas(data = data) %>%
  add_trace(
    x = ~x_net_worth, y = ~ reorder(y, x_saving),
    name = "Household net worth, Million USD/capita",
    type = "scatter", mode = "lines+markers",
    line = list(color = "rgb(128, 0, 128)")
  ) %>%
  layout(
    yaxis = list(
      showgrid = FALSE, showline = TRUE, showticklabels = FALSE,
      linecolor = "rgba(102, 102, 102, 0.8)", linewidth = 2,
      domain = c(0, 0.85)
    ),
    xaxis = list(
      zeroline = FALSE, showline = FALSE, showticklabels = TRUE,
      showgrid = TRUE, side = "top", dtick = 25000
    )
  ) %>%
  add_annotations(
    xref = "x2", yref = "y",
    x = x_net_worth, y = y,
    text = paste(x_net_worth, "M"),
    font = list(family = "Arial", size = 12, color = "rgb(128, 0, 128)"),
    showarrow = FALSE
  )

p <- subplot(p1, p2) %>%
  layout(
    title = list(text = "Household savings & net worth for eight OECD countries"),
    legend = list(x = 0.029, xanchor = "left", y = 1.038, font = list(size = 10)),
    margin = list(l = 100, r = 20, t = 70, b = 110),
    paper_bgcolor = "rgb(248, 248, 255)",
    plot_bgcolor = "rgb(248, 248, 255)"
  ) %>%
  add_annotations(
    xref = "paper", yref = "paper",
    x = -0.14, y = -0.15,
    text = paste("OECD (2015), Household savings (indicator), Household net worth (indicator). doi: 10.1787/cfc6f499-en (Accessed on 05 June 2015)"),
    font = list(family = "Arial", size = 10, color = "rgb(150,150,150)"),
    showarrow = FALSE
  )
p
LS0tDQp0aXRsZTogIkJhciBDaGFydCINCnN1YnRpdGxlOiAiIg0KYXV0aG9yOiAiSHVtb29uIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNzczogLi4vY3NzL3N0eWxlLmNzcw0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICB0aGVtZTogdW5pdGVkDQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICAgIHNtb290aF9zY3JvbGw6IHllcw0KZG9jdW1lbnRjbGFzczogY3RleGFydA0KY2xhc3NvcHRpb246IGh5cGVycmVmLA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQpzb3VyY2UoIi4uL2xpYi9SbWFya2Rvd25fY29uZmlnLlIiKQ0KDQojIyBnbG9iYWwgb3B0aW9ucyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICB3aWR0aCA9IGNvbmZpZyR3aWR0aCwNCiAgZmlnLndpZHRoID0gY29uZmlnJGZpZy53aWR0aCwNCiAgZmlnLmFzcCA9IGNvbmZpZyRmaWcuYXNwLA0KICBvdXQud2lkdGggPSBjb25maWckb3V0LndpZHRoLA0KICBmaWcuYWxpZ24gPSBjb25maWckZmlnLmFsaWduLA0KICBmaWcucGF0aCA9IGNvbmZpZyRmaWcucGF0aCwNCiAgZmlnLnNob3cgPSBjb25maWckZmlnLnNob3csDQogIHdhcm4gPSBjb25maWckd2FybiwNCiAgd2FybmluZyA9IGNvbmZpZyR3YXJuaW5nLA0KICBtZXNzYWdlID0gY29uZmlnJG1lc3NhZ2UsDQogIGVjaG8gPSBjb25maWckZWNobywNCiAgZXZhbCA9IGNvbmZpZyRldmFsLA0KICB0aWR5ID0gY29uZmlnJHRpZHksDQogIGNvbW1lbnQgPSBjb25maWckY29tbWVudCwNCiAgY29sbGFwc2UgPSBjb25maWckY29sbGFwc2UsDQogIGNhY2hlID0gY29uZmlnJGNhY2hlLA0KICBjYWNoZS5jb21tZW50cyA9IGNvbmZpZyRjYWNoZS5jb21tZW50cywNCiAgYXV0b2RlcCA9IGNvbmZpZyRhdXRvZGVwDQopDQpgYGANCg0KDQpgYGB7cn0NCnNvdXJjZSgiLi4vbGliL3Bsb3QtZWxlbWVudC5SIikNCmBgYA0KDQoNCiMjIOW5tuWIl+WSjOWghuWPoCwgR3JvdXAgYW5kIFN0YWNrDQoNCmBgYHtyfQ0KQW5pbWFscyA8LSBjKCJnaXJhZmZlcyIsICJvcmFuZ3V0YW5zIiwgIm1vbmtleXMiKQ0KU0ZfWm9vIDwtIGMoMjAsIDE0LCAyMykNCkxBX1pvbyA8LSBjKDEyLCAxOCwgMjkpDQpiYXJfZGF0YSA8LSBkYXRhLnRhYmxlKEFuaW1hbHMsIFNGX1pvbywgTEFfWm9vKQ0KDQpwMCA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBiYXJfZGF0YSwgeCA9IH5BbmltYWxzKSAlPiUNCiAgY29uZmlnKG1hdGhqYXggPSAiY2RuIikgJT4lDQogIGFkZF9iYXJzKA0KICAgIHkgPSB+U0ZfWm9vLA0KICAgIG5hbWUgPSAiU0YgWm9vIg0KICApICU+JQ0KICBhZGRfYmFycygNCiAgICB5ID0gfkxBX1pvbywNCiAgICBuYW1lID0gIkxBIFpvbyINCiAgKSAlPiUNCiAgbGF5b3V0KA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJBbmltYWxzIiksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkNvdW50IikNCiAgKQ0KDQpwIDwtIHAwICU+JQ0KICBsYXlvdXQoYmFybW9kZSA9ICJncm91cCIpDQpwDQoNCnAgPC0gcDAgJT4lDQogIGxheW91dChiYXJtb2RlID0gInN0YWNrIikNCnANCmBgYA0KDQojIyDmnaHkuIrmmL7npLrmlbDlgLwv5paH5pysDQoNCmBgYHtyfQ0KeCA8LSBjKCJQcm9kdWN0IEEiLCAiUHJvZHVjdCBCIiwgIlByb2R1Y3QgQyIpDQp5IDwtIGMoMjAsIDE0LCAyMykNCnkyIDwtIGMoMTYsIDEyLCAyNykNCnRleHQgPC0gYygiMjclIG1hcmtldCBzaGFyZSIsICIyNCUgbWFya2V0IHNoYXJlIiwgIjE5JSBtYXJrZXQgc2hhcmUiKQ0KYmFyX2RhdGEgPC0gZGF0YS50YWJsZSh4LCB5LCB5MiwgdGV4dCkNCg0KcDAgPC0gY3JlYXRlX2NhbnZhcygNCiAgZGF0YSA9IGJhcl9kYXRhLCB4ID0gfngsDQogICMgY29sb3IgPSBJKCJibGFjayIpLA0KICAjIEkoJy4uLicpIOeahOWumuS5ieS8muinhOWumuaJgOacieminOiJsu+8jOS4jeeUqOaKim1hcmtlcueahGNvbG9yLCBsaW5l55qEY29sb3LnrYnlhajpg6jlhpnkuIDpgY0NCiAgbWFya2VyID0gbGlzdCgNCiAgICBjb2xvciA9ICJyZ2IoMTU4LDIwMiwyMjUpIiwNCiAgICBsaW5lID0gbGlzdCgNCiAgICAgIGNvbG9yID0gInJnYig4LDQ4LDEwNykiLA0KICAgICAgd2lkdGggPSAxLjUNCiAgICApDQogICkNCikgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9IGxpc3QoDQogICAgICB0ZXh0ID0gIkphbnVhcnkgMjAxMyBTYWxlcyBSZXBvcnQiLA0KICAgICAgcGFkID0gbGlzdCh0ID0gNDApDQogICAgKSwNCiAgICBsZWdlbmQgPSBsaXN0KA0KICAgICAgYmdjb2xvciA9ICJ3aGl0ZSIsDQogICAgICB4YW5jaG9yID0gImxlZnQiDQogICAgKQ0KICApICU+JQ0KICBjb25maWcobWF0aGpheCA9ICJjZG4iKQ0KDQpwIDwtIHAwICU+JQ0KICBhZGRfYmFycyh5ID0gfnksIHRleHQgPSB+dGV4dCkNCnANCg0KcCA8LSBwMCAlPiUNCiAgYWRkX2JhcnMoeSA9IH55LCB0ZXh0ID0gfnkpDQpwDQoNCnAgPC0gcDAgJT4lDQogIGFkZF9iYXJzKHkgPSB+eSwgdGV4dCA9IH55LCBuYW1lID0gInkxIikgJT4lDQogIGFkZF9iYXJzKHkgPSB+eTIsIHRleHQgPSB+eTIsIG5hbWUgPSAieTIiKSAlPiUNCiAgbGF5b3V0KGJhcm1vZGUgPSAiZ3JvdXAiKQ0KcA0KYGBgDQoNCg0KDQojIyDovbTliLvluqbmoIfnrb7lgL7mlpwsIFJvdGF0ZWQgTGFiZWxzDQoNCmBgYHtyfQ0KeCA8LSBjKA0KICAiSmFudWFyeSIsICJGZWJydWFyeSIsICJNYXJjaCIsICJBcHJpbCIsICJNYXkiLCAiSnVuZSIsDQogICJKdWx5IiwgIkF1Z3VzdCIsICJTZXB0ZW1iZXIiLCAiT2N0b2JlciIsICJOb3ZlbWJlciIsICJEZWNlbWJlciINCikNCnkxIDwtIGMoMjAsIDE0LCAyNSwgMTYsIDE4LCAyMiwgMTksIDE1LCAxMiwgMTYsIDE0LCAxNykNCnkyIDwtIGMoMTksIDE0LCAyMiwgMTQsIDE2LCAxOSwgMTUsIDE0LCAxMCwgMTIsIDEyLCAxNikNCmRhdGEgPC0gZGF0YS50YWJsZSh4LCB5MSwgeTIpDQoNCiMgVGhlIGRlZmF1bHQgb3JkZXIgd2lsbCBiZSBhbHBoYWJldGl6ZWQgdW5sZXNzIHNwZWNpZmllZCBhcyBiZWxvdzoNCmRhdGEkeCA8LSBmYWN0b3IoZGF0YSR4LCBsZXZlbHMgPSBkYXRhW1sieCJdXSkNCg0KcDAgPC0gY3JlYXRlX2NhbnZhcyhkYXRhID0gZGF0YSwgeCA9IH54KSAlPiUNCiAgbGF5b3V0KA0KICAgIGxlZ2VuZCA9IGxpc3QoDQogICAgICBiZ2NvbG9yID0gIndoaXRlIiwNCiAgICAgIHhhbmNob3IgPSAibGVmdCINCiAgICApDQogICkNCg0KcCA8LSBwMCAlPiUNCiAgYWRkX2JhcnMoDQogICAgeSA9IH55MSwgbmFtZSA9ICJQcmltYXJ5IFByb2R1Y3QiLA0KICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmdiKDQ5LDEzMCwxODkpIikNCiAgKSAlPiUNCiAgYWRkX2JhcnMoDQogICAgeSA9IH55MiwgbmFtZSA9ICJTZWNvbmRhcnkgUHJvZHVjdCIsDQogICAgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZ2IoMjA0LDIwNCwyMDQpIikNCiAgKSAlPiUNCiAgbGF5b3V0KA0KICAgIHhheGlzID0gbGlzdCh0aWNrYW5nbGUgPSAtNDUpLA0KICAgIGJhcm1vZGUgPSAiZ3JvdXAiDQogICkNCnANCmBgYA0KDQoNCg0KIyMg6Ieq5a6a5LmJ5q+P5Liq5p2h55qE6aKc6ImyDQoNCmBgYHtyfQ0KeCA8LSBjKCJGZWF0dXJlIEEiLCAiRmVhdHVyZSBCIiwgIkZlYXR1cmUgQyIsICJGZWF0dXJlIEQiLCAiRmVhdHVyZSBFIikNCnkgPC0gYygyMCwgMTQsIDIzLCAyNSwgMjIpDQpkYXRhIDwtIGRhdGEudGFibGUoeCwgeSkNCg0KcCA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBkYXRhKSAlPiUNCiAgYWRkX2JhcnMoDQogICAgeCA9IH54LCB5ID0gfnksDQogICAgbWFya2VyID0gbGlzdCgNCiAgICAgIGNvbG9yID0gYygNCiAgICAgICAgInJnYmEoMjA0LDIwNCwyMDQsMSkiLCAicmdiYSgyMjIsNDUsMzgsMC44KSIsDQogICAgICAgICJyZ2JhKDIwNCwyMDQsMjA0LDEpIiwgInJnYmEoMjA0LDIwNCwyMDQsMSkiLA0KICAgICAgICAicmdiYSgyMDQsMjA0LDIwNCwxKSINCiAgICAgICkNCiAgICApDQogICkgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9IGxpc3QoDQogICAgICB0ZXh0ID0gIkxlYXN0IFVzZWQgRmVhdHVyZXMiLA0KICAgICAgcGFkID0gbGlzdCh0ID0gNDApDQogICAgKQ0KICApDQpwDQpgYGANCg0KDQojIyDoh6rlrprkuYnmr4/kuKrmnaHnmoTlrr3luqYNCg0KYGBge3J9DQp4IDwtIGMoMSwgMiwgMywgNS41LCAxMCkNCnkgPC0gYygxMCwgOCwgNiwgNCwgMikNCndpZHRoIDwtIGMoMC44LCAwLjgsIDAuOCwgMy41LCA0KQ0KZGF0YSA8LSBkYXRhLnRhYmxlKHgsIHksIHdpZHRoKQ0KDQpwIDwtIGNyZWF0ZV9jYW52YXMoZGF0YSA9IGRhdGEpICU+JQ0KICBhZGRfYmFycygNCiAgICB4ID0gfngsDQogICAgeSA9IH55LA0KICAgIHdpZHRoID0gfndpZHRoDQogICkNCnANCmBgYA0KDQoNCg0KIyMg6Ieq5a6a5LmJ5q+P5Liq5p2h55qE5Z+657q/6auY5bqm77yMQmFzZQ0KDQpgYGB7cn0NCnAgPC0gY3JlYXRlX2NhbnZhcyh4ID0gYygiMjAxNiIsICIyMDE3IiwgIjIwMTgiKSkgJT4lDQogIGFkZF9iYXJzKA0KICAgIHkgPSBjKDUwMCwgNjAwLCA3MDApLA0KICAgIGJhc2UgPSBjKC01MDAsIC02MDAsIC03MDApLA0KICAgIG1hcmtlciA9IGxpc3QoDQogICAgICBjb2xvciA9ICJvcmFuZ2VyZWQiDQogICAgKSwNCiAgICBuYW1lID0gImV4cGVuc2VzIg0KICApICU+JQ0KICBhZGRfYmFycygNCiAgICB5ID0gYygzMDAsIDQwMCwgNzAwKSwNCiAgICAjIGJhc2UgPSAwLA0KICAgIG1hcmtlciA9IGxpc3QoDQogICAgICBjb2xvciA9ICJyb3lhbGJsdWUiDQogICAgKSwNCiAgICBuYW1lID0gInJldmVudWUiDQogICkgJT4lDQogIGxheW91dCgNCiAgICBsZWdlbmQgPSBsaXN0KA0KICAgICAgYmdjb2xvciA9ICJ3aGl0ZSIsDQogICAgICB4YW5jaG9yID0gImxlZnQiDQogICAgKQ0KICApDQpwDQpgYGANCg0KDQojIyDmmKDlsITlj5jph4/kuLrpopzoibINCg0KYGBge3J9DQpkYXRhIDwtIGdncGxvdDI6OmRpYW1vbmRzICU+JQ0KICBjb3VudChjdXQsIGNsYXJpdHkpDQpkYXRhDQoNCnAgPC0gY3JlYXRlX2NhbnZhcyhkYXRhID0gZGF0YSkgJT4lDQogIGFkZF9iYXJzKHggPSB+Y3V0LCB5ID0gfm4sIGNvbG9yID0gfmNsYXJpdHkpICU+JQ0KICBsYXlvdXQoDQogICAgbGVnZW5kID0gbGlzdCgNCiAgICAgIGJnY29sb3IgPSAid2hpdGUiLA0KICAgICAgeGFuY2hvciA9ICJsZWZ0Ig0KICAgICkNCiAgKQ0KcA0KYGBgDQoNCg0KDQojIyDlrprkuYnmnaHpl7Tot50NCg0KYGBge3J9DQp4IDwtIGMoDQogIDE5OTUsIDE5OTYsIDE5OTcsIDE5OTgsIDE5OTksIDIwMDAsIDIwMDEsIDIwMDIsIDIwMDMsDQogIDIwMDQsIDIwMDUsIDIwMDYsIDIwMDcsIDIwMDgsIDIwMDksIDIwMTAsIDIwMTEsIDIwMTINCikNCnJvVyA8LSBjKA0KICAyMTksIDE0NiwgMTEyLCAxMjcsIDEyNCwgMTgwLCAyMzYsIDIwNywgMjM2LA0KICAyNjMsIDM1MCwgNDMwLCA0NzQsIDUyNiwgNDg4LCA1MzcsIDUwMCwgNDM5DQopDQpDaGluYSA8LSBjKA0KICAxNiwgMTMsIDEwLCAxMSwgMjgsIDM3LCA0MywgNTUsIDU2LA0KICA4OCwgMTA1LCAxNTYsIDI3MCwgMjk5LCAzNDAsIDQwMywgNTQ5LCA0OTkNCikNCmRhdGEgPC0gZGF0YS50YWJsZSh4LCByb1csIENoaW5hKQ0KDQpwMCA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBkYXRhLCB4ID0gfngpDQoNCnAgPC0gcDAgJT4lDQogIGFkZF9iYXJzKA0KICAgIHkgPSB+cm9XLCBuYW1lID0gIlJlc3Qgb2YgdGhlIFdvcmxkIiwNCiAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJnYig1NSwgODMsIDEwOSkiKQ0KICApICU+JQ0KICBhZGRfYmFycygNCiAgICB5ID0gfkNoaW5hLCBuYW1lID0gIkNoaW5hIiwNCiAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJnYigyNiwgMTE4LCAyNTUpIikNCiAgKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIlVTIEV4cG9ydCBvZiBQbGFzdGljIFNjcmFwIiksDQogICAgeGF4aXMgPSBsaXN0KA0KICAgICAgdGlja2ZvbnQgPSBsaXN0KA0KICAgICAgICBzaXplID0gMTQsDQogICAgICAgIGNvbG9yID0gInJnYigxMDcsIDEwNywgMTA3KSINCiAgICAgICkNCiAgICApLA0KICAgIHlheGlzID0gbGlzdCgNCiAgICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIlVTRCAobWlsbGlvbnMpIiksDQogICAgICB0aXRsZWZvbnQgPSBsaXN0KA0KICAgICAgICBzaXplID0gMTYsDQogICAgICAgIGNvbG9yID0gInJnYigxMDcsIDEwNywgMTA3KSINCiAgICAgICksDQogICAgICB0aWNrZm9udCA9IGxpc3QoDQogICAgICAgIHNpemUgPSAxNCwNCiAgICAgICAgY29sb3IgPSAicmdiKDEwNywgMTA3LCAxMDcpIg0KICAgICAgKQ0KICAgICksDQogICAgbGVnZW5kID0gbGlzdCgNCiAgICAgIHggPSAwLCB4YW5jaG9yID0gImxlZnQiLCB5ID0gMSwNCiAgICAgIGJnY29sb3IgPSAicmdiYSgyNTUsIDI1NSwgMjU1LCAwKSIgIyDpgI/mmI7luqbkuLowDQogICAgKSwNCiAgICBiYXJtb2RlID0gImdyb3VwIiwgYmFyZ2FwID0gMC4xNSwNCiAgICBiYXJncm91cGdhcCA9IDAuMSAjIOivpeWxnuaAp+aYjuaYjui1t+S9nOeUqO+8jOi/mOaYr+aKpXdhcm5pbmfor7TmsqHmnInov5nkuKrlsZ7mgKcNCiAgKQ0KcA0KYGBgDQoNCg0KIyMg54CR5biD5Zu+LCBXYXRlcmZhbGwNCg0KYGBge3J9DQp4IDwtIGMoDQogICJQcm9kdWN0PGJyPlJldmVudWUiLCAiU2VydmljZXM8YnI+UmV2ZW51ZSIsICJUb3RhbDxicj5SZXZlbnVlIiwNCiAgIkZpeGVkPGJyPkNvc3RzIiwgIlZhcmlhYmxlPGJyPkNvc3RzIiwgIlRvdGFsPGJyPkNvc3RzIiwgIlRvdGFsIg0KKQ0KeSA8LSBjKDQwMCwgNjYwLCA2NjAsIDU5MCwgNDAwLCA0MDAsIDM0MCkNCmJhc2UgPC0gYygwLCA0MzAsIDAsIDU3MCwgMzcwLCAzNzAsIDApDQpyZXZlbnVlIDwtIGMoNDMwLCAyNjAsIDY5MCwgMCwgMCwgMCwgMCkNCmNvc3RzIDwtIGMoMCwgMCwgMCwgMTIwLCAyMDAsIDMyMCwgMCkNCnByb2ZpdCA8LSBjKDAsIDAsIDAsIDAsIDAsIDAsIDM3MCkNCnRleHQgPC0gYygiJDQzMEsiLCAiJDI2MEsiLCAiJDY5MEsiLCAiJC0xMjBLIiwgIiQtMjAwSyIsICIkLTMyMEsiLCAiJDM3MEsiKQ0KZGF0YSA8LSBkYXRhLnRhYmxlKHgsIGJhc2UsIHJldmVudWUsIGNvc3RzLCBwcm9maXQsIHRleHQpDQoNCiMgVGhlIGRlZmF1bHQgb3JkZXIgd2lsbCBiZSBhbHBoYWJldGl6ZWQgdW5sZXNzIHNwZWNpZmllZCBhcyBiZWxvdzoNCmRhdGEkeCA8LSBmYWN0b3IoZGF0YSR4LCBsZXZlbHMgPSBkYXRhW1sieCJdXSkNCg0KcCA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBkYXRhLCB4ID0gfngpICU+JQ0KICAjIOWghuWPoOWxgu+8jOimgemAj+aYju+8jOaJjeiDveeci+i1t+adpeWDj+S7gOS5iOmDveayoeaciQ0KICBhZGRfYmFycygNCiAgICB5ID0gfmJhc2UsIG5hbWUgPSAiIiwNCiAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gInJnYmEoMSwxLDEsMCkiKQ0KICApICU+JQ0KICBhZGRfYmFycygNCiAgICB5ID0gfnJldmVudWUsIG5hbWUgPSAicmV2ZW51ZSIsDQogICAgbWFya2VyID0gbGlzdCgNCiAgICAgIGNvbG9yID0gInJnYmEoNTUsIDEyOCwgMTkxLCAwLjcpIiwNCiAgICAgIGxpbmUgPSBsaXN0KA0KICAgICAgICBjb2xvciA9ICJyZ2JhKDU1LCAxMjgsIDE5MSwgMC43KSIsDQogICAgICAgIHdpZHRoID0gMg0KICAgICAgKQ0KICAgICkNCiAgKSAlPiUNCiAgYWRkX2JhcnMoDQogICAgeSA9IH5jb3N0cywgbmFtZSA9ICJjb3N0IiwNCiAgICBtYXJrZXIgPSBsaXN0KA0KICAgICAgY29sb3IgPSAicmdiYSgyMTksIDY0LCA4MiwgMC43KSIsDQogICAgICBsaW5lID0gbGlzdCgNCiAgICAgICAgY29sb3IgPSAicmdiYSgyMTksIDY0LCA4MiwgMS4wKSIsDQogICAgICAgIHdpZHRoID0gMg0KICAgICAgKQ0KICAgICkNCiAgKSAlPiUNCiAgYWRkX2JhcnMoDQogICAgeSA9IH5wcm9maXQsIG5hbWUgPSAicHJvZml0IiwNCiAgICBtYXJrZXIgPSBsaXN0KA0KICAgICAgY29sb3IgPSAicmdiYSg1MCwgMTcxLCA5NiwgMC43KSIsDQogICAgICBsaW5lID0gbGlzdCgNCiAgICAgICAgY29sb3IgPSAicmdiYSg1MCwgMTcxLCA5NiwgMS4wKSIsDQogICAgICAgIHdpZHRoID0gMg0KICAgICAgKQ0KICAgICkNCiAgKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIkFubnVhbCBQcm9maXQgLSAyMDE1IiksDQogICAgYmFybW9kZSA9ICJzdGFjayIsDQogICAgc2hvd2xlZ2VuZCA9IFRSVUUNCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHRleHQgPSB+dGV4dCwNCiAgICB4ID0gfngsDQogICAgeSA9IH55LA0KICAgIHhyZWYgPSAieCIsDQogICAgeXJlZiA9ICJ5IiwNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsDQogICAgICBzaXplID0gMTQsDQogICAgICBjb2xvciA9ICJyZ2JhKDI0NSwgMjQ2LCAyNDksIDEpIg0KICAgICksDQogICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgKQ0KcA0KYGBgDQoNCg0KDQojIyDmsLTlubPmnaHlvaLlm74sIEhvcml6b250YWwNCg0KYGBge3J9DQp5IDwtIGMoImdpcmFmZmVzIiwgIm9yYW5ndXRhbnMiLCAibW9ua2V5cyIpDQpTRl9ab28gPC0gYygyMCwgMTQsIDIzKQ0KTEFfWm9vIDwtIGMoMTIsIDE4LCAyOSkNCmRhdGEgPC0gZGF0YS50YWJsZSh5LCBTRl9ab28sIExBX1pvbykNCg0KY3JlYXRlX2NhbnZhcyhkYXRhID0gZGF0YSkgJT4lDQogIGFkZF9iYXJzKA0KICAgIHggPSB+U0ZfWm9vLA0KICAgIHkgPSB+eSwNCiAgICBvcmllbnRhdGlvbiA9ICJoIg0KICApDQoNCnAgPC0gY3JlYXRlX2NhbnZhcyhkYXRhID0gZGF0YSwgeSA9IH55LCBvcmllbnRhdGlvbiA9ICJoIikgJT4lDQogIGFkZF90cmFjZSgNCiAgICB4ID0gflNGX1pvbywgbmFtZSA9ICJTRiBab28iLA0KICAgIG1hcmtlciA9IGxpc3QoDQogICAgICBjb2xvciA9ICJyZ2JhKDI0NiwgNzgsIDEzOSwgMC42KSIsDQogICAgICBsaW5lID0gbGlzdCgNCiAgICAgICAgY29sb3IgPSAicmdiYSgyNDYsIDc4LCAxMzksIDEuMCkiLA0KICAgICAgICB3aWR0aCA9IDMNCiAgICAgICkNCiAgICApDQogICkgJT4lDQogIGFkZF90cmFjZSgNCiAgICB4ID0gfkxBX1pvbywgbmFtZSA9ICJMQSBab28iLA0KICAgIG1hcmtlciA9IGxpc3QoDQogICAgICBjb2xvciA9ICJyZ2JhKDU4LCA3MSwgODAsIDAuNikiLA0KICAgICAgbGluZSA9IGxpc3QoDQogICAgICAgIGNvbG9yID0gInJnYmEoNTgsIDcxLCA4MCwgMS4wKSIsDQogICAgICAgIHdpZHRoID0gMw0KICAgICAgKQ0KICAgICkNCiAgKSAlPiUNCiAgbGF5b3V0KGJhcm1vZGUgPSAic3RhY2siKQ0KcA0KYGBgDQoNCmBgYHtyfQ0KeSA8LSBjKA0KICAiVGhlIGNvdXJzZSB3YXMgZWZmZWN0aXZlbHk8YnI+b3JnYW5pemVkIiwNCiAgIlRoZSBjb3Vyc2UgZGV2ZWxvcGVkIG15PGJyPmFiaWxpdGllcyBhbmQgc2tpbGxzIGZvcjxicj50aGUgc3ViamVjdCIsDQogICJUaGUgY291cnNlIGRldmVsb3BlZCBteTxicj5hYmlsaXR5IHRvIHRoaW5rIGNyaXRpY2FsbHkgYWJvdXQ8YnI+dGhlIHN1YmplY3QiLA0KICAiSSB3b3VsZCByZWNvbW1lbmQgdGhpczxicj5jb3Vyc2UgdG8gYSBmcmllbmQiDQopDQp4MSA8LSBjKDIxLCAyNCwgMjcsIDI5KQ0KeDIgPC0gYygzMCwgMzEsIDI2LCAyNCkNCngzIDwtIGMoMjEsIDE5LCAyMywgMTUpDQp4NCA8LSBjKDE2LCAxNSwgMTEsIDE4KQ0KeDUgPC0gYygxMiwgMTEsIDEzLCAxNCkNCg0KZGF0YSA8LSBkYXRhLnRhYmxlKHksIHgxLCB4MiwgeDMsIHg0LCB4NSkNCg0KdG9wX2xhYmVscyA8LSBjKA0KICAiU3Ryb25nbHk8YnI+YWdyZWUiLCAiQWdyZWUiLCAiTmV1dHJhbCIsDQogICJEaXNhZ3JlZSIsICJTdHJvbmdseTxicj5kaXNhZ3JlZSINCikNCg0KcDAgPC0gY3JlYXRlX2NhbnZhcygNCiAgZGF0YSA9IGRhdGEsIHkgPSB+eSwgb3JpZW50YXRpb24gPSAiaCIsDQogIG1hcmtlciA9IGxpc3QobGluZSA9IGxpc3QoDQogICAgY29sb3IgPSAicmdiKDI0OCwgMjQ4LCAyNDkpIiwNCiAgICB3aWR0aCA9IDENCiAgKSkNCikNCg0KcCA8LSBwMCAlPiUNCiAgYWRkX2JhcnMoeCA9IH54MSwgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZ2JhKDM4LCAyNCwgNzQsIDAuOCkiKSkgJT4lDQogIGFkZF9iYXJzKHggPSB+eDIsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmdiYSg3MSwgNTgsIDEzMSwgMC44KSIpKSAlPiUNCiAgYWRkX2JhcnMoeCA9IH54MywgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZ2JhKDEyMiwgMTIwLCAxNjgsIDAuOCkiKSkgJT4lDQogIGFkZF9iYXJzKHggPSB+eDQsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmdiYSgxNjQsIDE2MywgMjA0LCAwLjg1KSIpKSAlPiUNCiAgYWRkX2JhcnMoeCA9IH54NSwgbWFya2VyID0gbGlzdChjb2xvciA9ICJyZ2JhKDE5MCwgMTkyLCAyMTMsIDEpIikpICU+JQ0KICBsYXlvdXQoDQogICAgeGF4aXMgPSBsaXN0KA0KICAgICAgc2hvd2dyaWQgPSBGQUxTRSwNCiAgICAgIHNob3dsaW5lID0gRkFMU0UsDQogICAgICBzaG93dGlja2xhYmVscyA9IEZBTFNFLA0KICAgICAgemVyb2xpbmUgPSBGQUxTRSwNCiAgICAgIGRvbWFpbiA9IGMoMC4xNSwgMSkgIyBwbG90IDE1JSDnmoTlrr3luqbnqbrlh7rmnaUNCiAgICApLA0KICAgIHlheGlzID0gbGlzdCgNCiAgICAgIHNob3dncmlkID0gRkFMU0UsDQogICAgICBzaG93bGluZSA9IEZBTFNFLA0KICAgICAgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSwNCiAgICAgIHplcm9saW5lID0gRkFMU0UNCiAgICApLA0KICAgIGJhcm1vZGUgPSAic3RhY2siLA0KICAgIHBhcGVyX2JnY29sb3IgPSAicmdiKDI0OCwgMjQ4LCAyNTUpIiwNCiAgICBwbG90X2JnY29sb3IgPSAicmdiKDI0OCwgMjQ4LCAyNTUpIiwNCiAgICBtYXJnaW4gPSBsaXN0KGwgPSAxMjAsIHIgPSAxMCwgdCA9IDE0MCwgYiA9IDgwKSwNCiAgICBzaG93bGVnZW5kID0gRkFMU0UNCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAicGFwZXIiLCB4ID0gMC4xNCwgIyBwbG90IDE0JSDnmoTkvY3nva4NCiAgICB4YW5jaG9yID0gInJpZ2h0IiwgYWxpZ24gPSAicmlnaHQiLCAjIOWPs+Wvuem9kA0KICAgIHlyZWYgPSAieSIsIHkgPSB+eSwgIyDlr7nlh4Z56L205LiK55qEeeWdkOaghw0KICAgIHRleHQgPSB+eSwNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwNCiAgICAgIGNvbG9yID0gInJnYig2NywgNjcsIDY3KSINCiAgICApLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkgJT4lDQogICMgbGFiZWxpbmcgdGhlIHBlcmNlbnRhZ2VzIG9mIGVhY2ggYmFyICh4X2F4aXMpDQogIGFkZF9hbm5vdGF0aW9ucygNCiAgICB4cmVmID0gIngiLCB5cmVmID0gInkiLA0KICAgIHggPSB4MSAvIDIsIHkgPSB5LA0KICAgIHRleHQgPSBzdHJfYyhkYXRhJHgxLCAiJSIpLA0KICAgIGZvbnQgPSBsaXN0KA0KICAgICAgZmFtaWx5ID0gIkFyaWFsIiwgc2l6ZSA9IDEyLA0KICAgICAgY29sb3IgPSAicmdiKDI0OCwgMjQ4LCAyNTUpIg0KICAgICksDQogICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAieCIsIHlyZWYgPSAieSIsDQogICAgeCA9IHgxICsgeDIgLyAyLCB5ID0geSwNCiAgICB0ZXh0ID0gc3RyX2MoZGF0YSR4MiwgIiUiKSwNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwNCiAgICAgIGNvbG9yID0gInJnYigyNDgsIDI0OCwgMjU1KSINCiAgICApLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkgJT4lDQogIGFkZF9hbm5vdGF0aW9ucygNCiAgICB4cmVmID0gIngiLCB5cmVmID0gInkiLA0KICAgIHggPSB4MSArIHgyICsgeDMgLyAyLCB5ID0geSwNCiAgICB0ZXh0ID0gc3RyX2MoZGF0YSR4MywgIiUiKSwNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwNCiAgICAgIGNvbG9yID0gInJnYigyNDgsIDI0OCwgMjU1KSINCiAgICApLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkgJT4lDQogIGFkZF9hbm5vdGF0aW9ucygNCiAgICB4cmVmID0gIngiLCB5cmVmID0gInkiLA0KICAgIHggPSB4MSArIHgyICsgeDMgKyB4NCAvIDIsIHkgPSB5LA0KICAgIHRleHQgPSBzdHJfYyhkYXRhJHg0LCAiJSIpLA0KICAgIGZvbnQgPSBsaXN0KA0KICAgICAgZmFtaWx5ID0gIkFyaWFsIiwgc2l6ZSA9IDEyLA0KICAgICAgY29sb3IgPSAicmdiKDI0OCwgMjQ4LCAyNTUpIg0KICAgICksDQogICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAieCIsIHlyZWYgPSAieSIsDQogICAgeCA9IHgxICsgeDIgKyB4MyArIHg0ICsgeDUgLyAyLCB5ID0geSwNCiAgICB0ZXh0ID0gc3RyX2MoZGF0YSR4NSwgIiUiKSwNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwNCiAgICAgIGNvbG9yID0gInJnYigyNDgsIDI0OCwgMjU1KSINCiAgICApLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkgJT4lDQogICMgbGFiZWxpbmcgdGhlIGZpcnN0IExpa2VydCBzY2FsZSAob24gdGhlIHRvcCkNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAieCIsIHggPSBjKA0KICAgICAgMjEgLyAyLCAyMSArIDMwIC8gMiwgMjEgKyAzMCArIDIxIC8gMiwNCiAgICAgIDIxICsgMzAgKyAyMSArIDE2IC8gMiwgMjEgKyAzMCArIDIxICsgMTYgKyAxMiAvIDINCiAgICApLA0KICAgIHlyZWYgPSAicGFwZXIiLCB5ID0gMS4xNSwNCiAgICB0ZXh0ID0gdG9wX2xhYmVscywNCiAgICBmb250ID0gbGlzdCgNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwNCiAgICAgIGNvbG9yID0gInJnYig2NywgNjcsIDY3KSINCiAgICApLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkNCnANCmBgYA0KDQoNCiMjIOS4pOW8oOWbvuWQiOW5tg0KDQpgYGB7cn0NCnkgPC0gYygNCiAgIkphcGFuIiwgIlVuaXRlZCBLaW5nZG9tIiwgIkNhbmFkYSIsICJOZXRoZXJsYW5kcyIsDQogICJVbml0ZWQgU3RhdGVzIiwgIkJlbGdpdW0iLCAiU3dlZGVuIiwgIlN3aXR6ZXJsYW5kIg0KKQ0KeF9zYXZpbmcgPC0gYygxLjM1ODYsIDIuMjYyMywgNC45ODIyLCA2LjUwOTcsIDcuNDgxMiwgNy41MTMzLCAxNS4yMTQ4LCAxNy41MjA1KQ0KeF9uZXRfd29ydGggPC0gYygNCiAgOTM0NTMuOTIsIDgxNjY2LjU3LCA2OTg4OS42MiwgNzgzODEuNTMsDQogIDE0MTM5NS4zLCA5Mjk2OS4wMiwgNjYwOTAuMTgsIDEyMjM3OS4zDQopDQpkYXRhIDwtIGRhdGEudGFibGUoeSwgeF9zYXZpbmcsIHhfbmV0X3dvcnRoKQ0KDQpwMSA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBkYXRhKSAlPiUNCiAgYWRkX2JhcnMoDQogICAgeCA9IH54X3NhdmluZywgeSA9IH4gcmVvcmRlcih5LCB4X3NhdmluZyksIG9yaWVudGF0aW9uID0gImgiLA0KICAgIG5hbWUgPSAiSG91c2Vob2xkIHNhdmluZ3MsIHBlcmNlbnRhZ2Ugb2YgaG91c2Vob2xkIGRpc3Bvc2FibGUgaW5jb21lIiwNCiAgICBtYXJrZXIgPSBsaXN0KA0KICAgICAgY29sb3IgPSAicmdiYSg1MCwgMTcxLCA5NiwgMC42KSIsDQogICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJyZ2JhKDUwLCAxNzEsIDk2LCAxKSIsIHdpZHRoID0gMSkNCiAgICApDQogICkgJT4lDQogIGxheW91dCgNCiAgICB5YXhpcyA9IGxpc3QoDQogICAgICBzaG93Z3JpZCA9IEZBTFNFLCBzaG93bGluZSA9IEZBTFNFLA0KICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLCBkb21haW4gPSBjKDAsIDAuODUpDQogICAgKSwNCiAgICB4YXhpcyA9IGxpc3QoDQogICAgICB6ZXJvbGluZSA9IEZBTFNFLCBzaG93bGluZSA9IEZBTFNFLA0KICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLCBzaG93Z3JpZCA9IFRSVUUNCiAgICApDQogICkgJT4lDQogIGFkZF9hbm5vdGF0aW9ucygNCiAgICB4cmVmID0gIngxIiwgeXJlZiA9ICJ5IiwNCiAgICB4ID0geF9zYXZpbmcgKyAyLA0KICAgIHkgPSB5LA0KICAgIHRleHQgPSBwYXN0ZShyb3VuZCh4X3NhdmluZywgMiksICIlIiksDQogICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIkFyaWFsIiwgc2l6ZSA9IDEyLCBjb2xvciA9ICJyZ2IoNTAsIDE3MSwgOTYpIiksDQogICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgKQ0KDQpwMiA8LSBjcmVhdGVfY2FudmFzKGRhdGEgPSBkYXRhKSAlPiUNCiAgYWRkX3RyYWNlKA0KICAgIHggPSB+eF9uZXRfd29ydGgsIHkgPSB+IHJlb3JkZXIoeSwgeF9zYXZpbmcpLA0KICAgIG5hbWUgPSAiSG91c2Vob2xkIG5ldCB3b3J0aCwgTWlsbGlvbiBVU0QvY2FwaXRhIiwNCiAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gImxpbmVzK21hcmtlcnMiLA0KICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJnYigxMjgsIDAsIDEyOCkiKQ0KICApICU+JQ0KICBsYXlvdXQoDQogICAgeWF4aXMgPSBsaXN0KA0KICAgICAgc2hvd2dyaWQgPSBGQUxTRSwgc2hvd2xpbmUgPSBUUlVFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFLA0KICAgICAgbGluZWNvbG9yID0gInJnYmEoMTAyLCAxMDIsIDEwMiwgMC44KSIsIGxpbmV3aWR0aCA9IDIsDQogICAgICBkb21haW4gPSBjKDAsIDAuODUpDQogICAgKSwNCiAgICB4YXhpcyA9IGxpc3QoDQogICAgICB6ZXJvbGluZSA9IEZBTFNFLCBzaG93bGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IFRSVUUsDQogICAgICBzaG93Z3JpZCA9IFRSVUUsIHNpZGUgPSAidG9wIiwgZHRpY2sgPSAyNTAwMA0KICAgICkNCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAieDIiLCB5cmVmID0gInkiLA0KICAgIHggPSB4X25ldF93b3J0aCwgeSA9IHksDQogICAgdGV4dCA9IHBhc3RlKHhfbmV0X3dvcnRoLCAiTSIpLA0KICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJBcmlhbCIsIHNpemUgPSAxMiwgY29sb3IgPSAicmdiKDEyOCwgMCwgMTI4KSIpLA0KICAgIHNob3dhcnJvdyA9IEZBTFNFDQogICkNCg0KcCA8LSBzdWJwbG90KHAxLCBwMikgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICJIb3VzZWhvbGQgc2F2aW5ncyAmIG5ldCB3b3J0aCBmb3IgZWlnaHQgT0VDRCBjb3VudHJpZXMiKSwNCiAgICBsZWdlbmQgPSBsaXN0KHggPSAwLjAyOSwgeGFuY2hvciA9ICJsZWZ0IiwgeSA9IDEuMDM4LCBmb250ID0gbGlzdChzaXplID0gMTApKSwNCiAgICBtYXJnaW4gPSBsaXN0KGwgPSAxMDAsIHIgPSAyMCwgdCA9IDcwLCBiID0gMTEwKSwNCiAgICBwYXBlcl9iZ2NvbG9yID0gInJnYigyNDgsIDI0OCwgMjU1KSIsDQogICAgcGxvdF9iZ2NvbG9yID0gInJnYigyNDgsIDI0OCwgMjU1KSINCiAgKSAlPiUNCiAgYWRkX2Fubm90YXRpb25zKA0KICAgIHhyZWYgPSAicGFwZXIiLCB5cmVmID0gInBhcGVyIiwNCiAgICB4ID0gLTAuMTQsIHkgPSAtMC4xNSwNCiAgICB0ZXh0ID0gcGFzdGUoIk9FQ0QgKDIwMTUpLCBIb3VzZWhvbGQgc2F2aW5ncyAoaW5kaWNhdG9yKSwgSG91c2Vob2xkIG5ldCB3b3J0aCAoaW5kaWNhdG9yKS4gZG9pOiAxMC4xNzg3L2NmYzZmNDk5LWVuIChBY2Nlc3NlZCBvbiAwNSBKdW5lIDIwMTUpIiksDQogICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIkFyaWFsIiwgc2l6ZSA9IDEwLCBjb2xvciA9ICJyZ2IoMTUwLDE1MCwxNTApIiksDQogICAgc2hvd2Fycm93ID0gRkFMU0UNCiAgKQ0KcA0KYGBgDQo=